]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
panel: Add a screen recording indicator
authorIvan Molodetskikh <yalterz@gmail.com>
Tue, 8 Feb 2022 16:18:01 +0000 (19:18 +0300)
committerMarge Bot <marge-bot@gnome.org>
Sat, 12 Feb 2022 14:36:54 +0000 (14:36 +0000)
The indicator shows the recording duration and lets the user stop it on
click. It is more discoverable than the stop entry in the aggregate
menu.

The class extends ButtonBox directly rather than Button because Button
does nothing that it uses, and actually causes issues with its dummy
menu (its vfunc_hide() throws an "open-state-changed: Error: incorrect
pop").

The menu-set signal declaration is required by the panel.

The screencast is stopped upon button press in vfunc_event(), which
matches PanelMenu.Button's input handling.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2163>

data/theme/gnome-shell-sass/widgets/_panel.scss
js/ui/panel.js
js/ui/sessionMode.js
js/ui/status/remoteAccess.js

index 7e577e828cb0b1650f9e6f6ae4e3a784715d24a1..feeb1a7a2477d93a6270dd949c92269086e5b473 100644 (file)
@@ -38,6 +38,18 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
       }
     }
 
+    &.screen-recording-indicator {
+      box-shadow: inset 0 0 0 100px $screenshot_ui_button_red;
+
+      StBoxLayout {
+        spacing: $base_spacing;
+      }
+
+      StIcon {
+        icon-size: $base_icon_size;
+      }
+    }
+
     &:active, &:overview, &:focus, &:checked {
       box-shadow: inset 0 0 0 100px transparentize($panel_fg_color, 0.8);
 
@@ -50,6 +62,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
           box-shadow: inset 0 0 0 100px transparentize($panel_fg_color, 0.8);
         }
       }
+
+      &.screen-recording-indicator {
+        box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.15);
+      }
     }
 
     &:hover {
@@ -60,6 +76,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
           box-shadow: inset 0 0 0 100px transparentize($panel_fg_color, 0.85);
         }
       }
+
+      &.screen-recording-indicator {
+        box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.1);
+      }
     }
     
     &:active:hover, &:overview:hover, &:focus:hover, &:checked:hover {
@@ -70,6 +90,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
           box-shadow: inset 0 0 0 100px transparentize($panel_fg_color, 0.75);
         }
       }
+
+      &.screen-recording-indicator {
+        box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.2);
+      }
     }
 
     // status area icons
@@ -109,6 +133,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
             box-shadow: inset 0 0 0 100px rgba(255,255,255, 0.15);
           }
         }
+
+        &.screen-recording-indicator {
+          box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.15);
+        }
       }
 
       &:hover {
@@ -119,6 +147,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
             box-shadow: inset 0 0 0 100px rgba(255,255,255, 0.10);
           }
         }
+
+        &.screen-recording-indicator {
+          box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.1);
+        }
       }
       
       &:active:hover, &:overview:hover, &:focus:hover, &:checked:hover {
@@ -129,6 +161,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
             box-shadow: inset 0 0 0 100px rgba(255,255,255, 0.2);
           }
         }
+
+        &.screen-recording-indicator {
+          box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.2);
+        }
       }
     }
   }
index ea40998a51b79dc82c62df30da2250dff2794bd4..78064f73f3f61b894070122a97d27fa91c366fbf 100644 (file)
@@ -468,6 +468,7 @@ const PANEL_ITEM_IMPLEMENTATIONS = {
     'a11y': imports.ui.status.accessibility.ATIndicator,
     'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
     'dwellClick': imports.ui.status.dwellClick.DwellClickIndicator,
+    'screenRecording': imports.ui.status.remoteAccess.ScreenRecordingIndicator,
 };
 
 var Panel = GObject.registerClass(
index 92d91fc604f7eb14c1373b3545d80c2c37791621..7d83ddb6be300cc33e94ff3e3d245ad79046ffc5 100644 (file)
@@ -91,7 +91,7 @@ const _modes = {
         panel: {
             left: ['activities', 'appMenu'],
             center: ['dateMenu'],
-            right: ['dwellClick', 'a11y', 'keyboard', 'aggregateMenu'],
+            right: ['screenRecording', 'dwellClick', 'a11y', 'keyboard', 'aggregateMenu'],
         },
     },
 };
index d6d500caedc9afe1122840b4b2c5c03109cfed90..a63b257c509aef98bb51f707d8f4fed3c3359d66 100644 (file)
@@ -1,7 +1,7 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-/* exported RemoteAccessApplet */
+/* exported RemoteAccessApplet, ScreenRecordingIndicator */
 
-const { GObject, Meta } = imports.gi;
+const { Atk, Clutter, GLib, GObject, Meta, St } = imports.gi;
 
 const Main = imports.ui.main;
 const PanelMenu = imports.ui.panelMenu;
@@ -106,3 +106,73 @@ class RemoteAccessApplet extends PanelMenu.SystemIndicator {
         this._sync();
     }
 });
+
+var ScreenRecordingIndicator = GObject.registerClass({
+    Signals: { 'menu-set': {} },
+}, class ScreenRecordingIndicator extends PanelMenu.ButtonBox {
+    _init() {
+        super._init({
+            reactive: true,
+            can_focus: true,
+            track_hover: true,
+            accessible_name: _('Stop Screencast'),
+            accessible_role: Atk.Role.PUSH_BUTTON,
+        });
+        this.add_style_class_name('screen-recording-indicator');
+
+        this._box = new St.BoxLayout();
+        this.add_child(this._box);
+
+        this._label = new St.Label({
+            text: '0:00',
+            y_align: Clutter.ActorAlign.CENTER,
+        });
+        this._box.add_child(this._label);
+
+        this._icon = new St.Icon({ icon_name: 'stop-symbolic' });
+        this._box.add_child(this._icon);
+
+        this.hide();
+        Main.screenshotUI.connect(
+            'notify::screencast-in-progress',
+            this._onScreencastInProgressChanged.bind(this));
+    }
+
+    vfunc_event(event) {
+        if (event.type() === Clutter.EventType.TOUCH_BEGIN ||
+            event.type() === Clutter.EventType.BUTTON_PRESS)
+            Main.screenshotUI.stopScreencast();
+
+        return Clutter.EVENT_PROPAGATE;
+    }
+
+    _updateLabel() {
+        const minutes = this._secondsPassed / 60;
+        const seconds = this._secondsPassed % 60;
+        this._label.text = '%d:%02d'.format(minutes, seconds);
+    }
+
+    _onScreencastInProgressChanged() {
+        if (Main.screenshotUI.screencast_in_progress) {
+            this.show();
+
+            this._secondsPassed = 0;
+            this._updateLabel();
+
+            this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => {
+                this._secondsPassed += 1;
+                this._updateLabel();
+                return GLib.SOURCE_CONTINUE;
+            });
+            GLib.Source.set_name_by_id(
+                this._timeoutId, '[gnome-shell] screen recording indicator tick');
+        } else {
+            this.hide();
+
+            GLib.source_remove(this._timeoutId);
+            delete this._timeoutId;
+
+            delete this._secondsPassed;
+        }
+    }
+});